package org.eae.eldf.framework.security.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import org.eae.eldf.entity.sys.Authorization;
import org.eae.eldf.entity.sys.SysPurview;
import org.eae.eldf.framework.spring.SpringSecurityUtils;




/**
 * 
 * 最核心的地方，就是提供某个资源对应的权限定义，即getAttributes方法返回的结果。
 * 注意，我例子中使用的是AntUrlPathMatcher这个path matcher来检查URL是否与资源定义匹配，
 * 事实上你还要用正则的方式来匹配，或者自己实现一个matcher。
 * 
 * 此类在初始化时，应该取到所有资源及其对应角色的定义
 * 
 * 说明：对于方法的spring注入，只能在方法和成员变量里注入， 如果一个类要进行实例化的时候，不能注入对象和操作对象，
 * 所以在构造函数里不能进行操作注入的数据。
 */
@Service
public class MyInvocationSecurityMetadataSourceService implements
		FilterInvocationSecurityMetadataSource {

	private static Log log = LogFactory
			.getLog(MyInvocationSecurityMetadataSourceService.class);


	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public MyInvocationSecurityMetadataSourceService() {
		loadResourceDefine();
	}

	private void loadResourceDefine() {
		try {
			ApplicationContext context = new ClassPathXmlApplicationContext(
					"applicationContext-resource.xml");
			JdbcTemplate template = (JdbcTemplate) context
					.getBean("jdbcTemplate");
			
			// 设置全局不区分大小写
			resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
			Collection<ConfigAttribute> atts;
			
			List<SysPurview> list = template.query("SELECT * FROM SYS_PURVIEW", new BeanPropertyRowMapper(SysPurview.class));
			for (SysPurview pur : list) {
				if (pur.getSurlpath().contains(";")) {
					String[] temp = pur.getSurlpath().split(";");
					for (int i = 0; i < temp.length; i++) {
						if (resourceMap.containsKey(temp[i])) {
							Collection<ConfigAttribute> value = resourceMap
									.get(temp[i]);
							ConfigAttribute ca = new SecurityConfig(
									pur.getSurlpath());
							value.add(ca);
							resourceMap.put(temp[i], value);
						} else {
							atts = new ArrayList<ConfigAttribute>();
							ConfigAttribute ca = new SecurityConfig(
									pur.getSurlpath());
							atts.add(ca);
							resourceMap.put(temp[i], atts);
						}
					}
				} else {
					// 打印所有权限信息
					if (resourceMap.containsKey(pur.getSurlpath())) {
						Collection<ConfigAttribute> value = resourceMap.get(pur
								.getSurlpath());
						ConfigAttribute ca = new SecurityConfig(
								pur.getSurlpath());
						value.add(ca);
						resourceMap.put(pur.getSurlpath(), value);
					} else {
						atts = new ArrayList<ConfigAttribute>();
						ConfigAttribute ca = new SecurityConfig(
								pur.getSurlpath());
						atts.add(ca);
						resourceMap.put(pur.getSurlpath(), atts);
					}
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/***
	 * 通过这个方法，可以根据URL获取到对这个URL的权限定义 次方法需要重写
	 */
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		// 三个对象的定义
		FilterInvocation fi = (FilterInvocation) object;
		String url = fi.getRequestUrl();
		log.info("--------------------->当前有参URL：" + url);
		if (url.indexOf("?") != -1) {// 有参数的路径
			url = url.split("\\?")[0];
		}
		Iterator<String> ite = resourceMap.keySet().iterator();
		while (ite.hasNext()) {
			String resURL = ite.next();
			if (url.equals(resURL.trim())) {
				return resourceMap.get(resURL);
			}
		}
		return null;
	}

	public boolean supports(Class<?> clazz) {
		return true;
	}

	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return null;
	}

}